/**
 * Copyright (c) 2011 The MITRE Corporation. All rights reserved.
 *
 * NOTICE
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-11-C-0001, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 */
package org.mitre.edxl.lib;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Class To Represent an EDXL-DE Message
 *
 * @author Danny Gagne
 * @author Rob Gustafson
 * @author Brian Wilkins
 * @author Greg Kern
 */
public class EDXLDE {

  /**
   * Enum for the possible Distribution Statuses.
   */
  public enum DistributionStatusEnum {
    NotSet, Actual, Exercise, System, Test
  };

  /**
   * Enum for the possible Distribution Types.
   */
  public enum DistributionTypeEnum {
    NotSet, Report, Update, Cancel, Request, Response, Dispatch, Ack, Error,
    SensorConfiguration, SensorControl, SensorStatus, SensorDetection
  };

  private String distributionID;
  private String senderID;
  private String combinedConfidentiality;
  private String language;

  private List<String> distributionReference;

  private Date datetimeSent;

  private DistributionStatusEnum distributionStatus;
  private DistributionTypeEnum distributionType;

  private List<EDXLStringList> senderRole;
  private List<EDXLStringList> recipientRole;
  private List<EDXLStringList> keyword;
  private List<EDXLStringList> explicitAddress;

  private List<TargetArea> targetArea;

  private List<ContentObject> contentObject;

  /**
   * Returns a XML representation of the EDXLDE object.
   *
   * @return A String of the XML representation of the EDXLDE object.
   */
  public String toXML() {
    StringBuilder sb = new StringBuilder();

    sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>");

    sb.append("<EDXLDistribution xmlns=\"urn:oasis:names:tc:emergency:EDXL:DE:1.0\">");

    sb.append(addStringElement(this.distributionID, "distributionID"));
    sb.append(addStringElement(this.senderID, "senderID"));
    sb.append(addDateTimeElement(this.datetimeSent, "dateTimeSent"));
    sb.append(addStringElement(this.distributionStatus.toString() ,
        "distributionStatus"));
    sb.append(addStringElement(this.distributionType.toString() ,
        "distributionType"));
    sb.append(addStringElement(this.combinedConfidentiality,
        "combinedConfidentiality"));
    sb.append(addStringElement(this.language, "language"));
    sb.append(addEDXLStringListElement(this.senderRole, "senderRole"));
    sb.append(addEDXLStringListElement(this.recipientRole, "recipientRole"));
    sb.append(addEDXLStringListElement(this.keyword, "keyword"));
    sb.append(addStringListElement(this.distributionReference,
        "distributionReference"));
    sb.append(addEDXLStringListElement(this.explicitAddress, "explicitAddress"));
    sb.append(addTargetAreaListElement(this.targetArea, "targetArea"));
    sb.append(addContentListElement(this.contentObject, "contentObject"));

    sb.append("</EDXLDistribution>");

    return sb.toString();
  }

  /**
   * Adds a Sender Role to the Sender Role list.
   *
   * @param val The new Sender Role to be added to the list.
   */
  public void addSenderRole(EDXLStringList val) {
    this.senderRole = addToList(this.senderRole, val);
  }

  /**
   * Adds a Recipient Role to the Recipient Role list.
   *
   * @param val The new Recipient Role to be added to the list.
   */
  public void addRecipientRole(EDXLStringList val) {
    this.recipientRole = addToList(this.recipientRole, val);
  }

  /**
   * Adds a Keyword to the Keyword list.
   *
   * @param val The new Keyword to be added to the list.
   */
  public void addKeyword(EDXLStringList val) {
    this.keyword = addToList(this.keyword, val);
  }

  /**
   * Adds a Address to the Address list.
   *
   * @param val The new Address to be added to the list.
   */
  public void addAddress(EDXLStringList val) {
    this.explicitAddress = addToList(this.explicitAddress, val);
  }

  /**
   * Adds a Target Area to the Target Area list.
   *
   * @param val The new Target Area to be added to the list.
   */
  public void addTargetArea(TargetArea val) {
    this.targetArea = addToList(this.targetArea, val);
  }

  /**
   * Adds a Content to the Content list.
   *
   * @param val The new Content to be added to the list.
   */
  public void addContent(ContentObject val) {
    this.contentObject = addToList(this.contentObject, val);
  }

  /**
   * Adds a Distribution Reference to the Distribution Reference list.
   *
   * @param val The new Distribution Reference to be added to the list.
   */
  public void addDistributionReference(String val) {
    this.distributionReference = addToList(this.distributionReference, val);
  }

  /**
   * Utility method that take in a list, initializes the list if needed,
   * added the need item to the list, and returns the updated list.
   *
   * @param list The list to which the new value will be added to.
   * @param val The new value to be added to the list.
   * @return Updated version of the original list containing the new value.
   */
  private <T> List<T> addToList(List<T> list, T val) {
    if (list == null) {
      list = new ArrayList<T>();
    }
    list.add(val);

    return list;
  }

  /**
   * Creates a String of XML elements with the given name, one for each
   * value in the Content Object list.
   *
   * @param valList The list of Content Object values to add XML element for.
   * @param elementName The name that should be given to the XML element.
   * @return The String containing the a series of XML elements.
   */
  private String addContentListElement(List<ContentObject> valList,
      String elementName) {
    String temp = "";

    if (valList != null) {
      for (ContentObject val : valList) {
        temp += addStringElement(val.toXML() , elementName);
      }
    }

    return temp;
  }

  /**
   * Creates a String of XML elements with the given name, one for each
   * value in the Target Area list.
   *
   * @param valList The list of Target Area values to add XML element for.
   * @param elementName The name that should be given to the XML element.
   * @return The String containing the a series of XML elements.
   */
  private String addTargetAreaListElement(List<TargetArea> valList,
      String elementName) {
    String temp = "";

    if (valList != null) {
      for (TargetArea val : valList) {
        temp += addStringElement(val.toXML() , elementName);
      }
    }

    return temp;
  }

  /**
   * Creates a String of XML elements with the given name, one for each
   * value in the EDXL String list.
   *
   * @param valList The list of EDXL String values to add XML element for.
   * @param elementName The name that should be given to the XML element.
   * @return The String containing the a series of XML elements.
   */
  private String addEDXLStringListElement(List<EDXLStringList> valList,
      String elementName) {
    String temp = "";

    if (valList != null) {
      for (EDXLStringList val : valList) {
        temp += addStringElement(val.toXML() , elementName);
      }
    }

    return temp;
  }

  /**
   * Creates a String of XML elements with the given name, one for each
   * value in the list.
   *
   * @param valList The list of values to add XML element for.
   * @param elementName The name that should be given to the XML element.
   * @return The String containing the a series of XML elements.
   */
  private String addStringListElement(List<String> valList, String elementName) {
    String temp = "";

    if (valList != null) {
      for (String val : valList) {
        temp += addStringElement(val , elementName);
      }
    }

    return temp;
  }

  /**
   * Creates a String of a XML element with the given name for the given value.
   *
   * @param val The value for the XML element.
   * @param elementName The name that should be given to the XML element.
   * @return The String of the XML element.
   */
  private String addStringElement(String val, String elementName) {
    String temp = "";

    if (val != null) {
      temp += "<" + elementName + ">" + val + "</" + elementName + ">";
    }

    return temp;
  }

  /**
   * Creates a String of a XML element with the given name for the given Date
   * value.
   *
   * @param val The Date value for the XML element.
   * @param elementName The name that should be given to the XML element.
   * @return The String of the XML element.
   */
  private String addDateTimeElement(Date val, String elementName) {
    String temp = "";
    Format formatter;

    if (val != null) {
      formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

      String ds = formatter.format(val);
      ds = ds.substring(0, ds.length() - 2) + ":"
          + ds.substring(ds.length() - 2);

      temp += addStringElement(ds, elementName);
    }

    return temp;

  }

  /**
   * Set the list of the Target Area values.
   *
   * @param val The list to set the Target Area values to.
   */
  public void setTargetArea(List<TargetArea> val) {
    this.targetArea = val;
  }

  /**
   * Get the list of values for the Target Area.
   *
   * @return The list of the Target Area values.
   */
  public List<TargetArea> getTargetArea() {
    return this.targetArea;
  }

  /**
   * Set the list of the Sender Role values.
   *
   * @param val The list to set the Sender Role values to.
   */
  public void setSenderRole(List<EDXLStringList> val) {
    this.senderRole = val;
  }

  /**
   * Get the list of values for the Sender Role.
   *
   * @return The list of the Sender Role values.
   */
  public List<EDXLStringList> getSenderRole() {
    return this.senderRole;
  }

  /**
   * Set the list of the Recipient Role values.
   *
   * @param val The list to set the Recipient Role values to.
   */
  public void setRecipientRole(List<EDXLStringList> val) {
    this.recipientRole = val;
  }

  /**
   * Get the list of values for the Recipient Role.
   *
   * @return The list of the Recipient Role values.
   */
  public List<EDXLStringList> getRecipientRole() {
    return this.recipientRole;
  }

  /**
   * Set the list of the Keyword values.
   *
   * @param val The list to set the Keyword values to.
   */
  public void setKeyword(List<EDXLStringList> val) {
    this.keyword = val;
  }

  /**
   * Get the list of values for the Keyword.
   *
   * @return The list value of the Keyword values.
   */
  public List<EDXLStringList> getKeyword() {
    return this.keyword;
  }

  /**
   * Set the list of the Explicit Address values.
   *
   * @param val The list to set the Explicit Address values to.
   */
  public void setExplicitAddress(List<EDXLStringList> val) {
    this.explicitAddress = val;
  }

  /**
   * Get the list of values for the Explicit Address.
   *
   * @return The list value of the Explicit Address values.
   */
  public List<EDXLStringList> getExplicitAddress() {
    return this.explicitAddress;
  }

  /**
   * Set the Distribution Identifier value.
   *
   * @param val The value to set the Distribution Identifier to.
   */
  public void setDistributionID(String val) {
    this.distributionID = val;
  }

  /**
   * Get the value for the Distribution Identifier.
   *
   * @return The String value of the Distribution Identifier.
   */
  public String getDistributionID() {
    return this.distributionID;
  }

  /**
   * Set the Sender Identifier value.
   *
   * @param val The value to set the Sender Identifier to.
   */
  public void setSenderID(String val) {
    this.senderID = val;
  }

  /**
   * Get the value for the Sender Identifier.
   *
   * @return The String value of the Sender Identifier.
   */
  public String getSenderID() {
    return this.senderID;
  }

  /**
   * Set the Combined Confidentiality value.
   *
   * @param val The value to set the Combined Confidentiality to.
   */
  public void setCombinedConfidentiality(String val) {
    this.combinedConfidentiality = val;
  }

  /**
   * Get the value for the Combined Confidentiality.
   *
   * @return The String value of the Combined Confidentiality.
   */
  public String getCombinedConfidentiality() {
    return this.combinedConfidentiality;
  }

  /**
   * Set the Language value.
   *
   * @param val The value to set the Language to.
   */
  public void setLanguage(String val) {
    this.language = val;
  }

  /**
   * Get the value for the Language.
   *
   * @return The String value of the Language.
   */
  public String getLanguage() {
    return this.language;
  }

  /**
   * Set the list of the Distribution Reference values.
   *
   * @param val The list to set the Distribution Reference values to.
   */
  public void setDistributionReference(List<String> val) {
    this.distributionReference = val;
  }

  /**
   * Get the list of values for the Distribution Reference.
   *
   * @return The list value of the Distribution Reference values.
   */
  public List<String> getDistributionReference() {
    return this.distributionReference;
  }

  /**
   * Set the Date/Time Sent value.
   *
   * @param val The value to set the Date/Time Sent to.
   */
  public void setDateTimeSent(Date val) {
    this.datetimeSent = val;
  }

  /**
   * Get the value for the Date/Time Sent.
   *
   * @return The Date value of the Date/Time Sent.
   */
  public Date getDateTimeSent() {
    return this.datetimeSent;
  }

  /**
   * Set the Date/Time Sent value as a String.
   *
   * @param val The value to set the Date/Time Sent to as a String.
   */
  public void setDateTimeSent(String val) {
    try {
      Format formatter;

      formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
      this.datetimeSent = (Date) formatter.parseObject(val);
    } catch (Exception e) {
      //
    }

  }

  /**
   * Get the value for the Date/Time Sent as a String.
   *
   * @return The String value of the Date/Time Sent.
   */
  public String getDateTimeSentAsString() {
    Format formatter;

    formatter = new SimpleDateFormat("yyyy-MM-ddTHH:mm:ssZ");

    return formatter.format(this.datetimeSent);
  }

  /**
   * Set the Distribution Status value.
   *
   * @param val The value to set the Distribution Status to.
   */
  public void setDistributionStatus(DistributionStatusEnum val) {
    this.distributionStatus = val;
  }

  /**
   * Get the value for the Distribution Status.
   *
   * @return The DistributionStatusEnum value of the Distribution Status.
   */
  public DistributionStatusEnum getDistributionStatus() {
    return this.distributionStatus;
  }

  /**
   * Set the Distribution Type value.
   *
   * @param val The value to set the Distribution Type to.
   */
  public void setDistributionType(DistributionTypeEnum val) {
    this.distributionType = val;
  }

  /**
   * Get the value for the Distribution Type.
   *
   * @return The DistributionTypeEnum value of the Distribution Type.
   */
  public DistributionTypeEnum getDistributionType() {
    return this.distributionType;
  }
}
